#include "CallingContext.hpp"

#include "SymbolTable.hpp"
#include "CallingInstance.hpp"
#include "ProgramManager.hpp"

#include "Instruction.hpp"

CallingContext::CallingContext () :
    _code ( NULL ),
    _symbols ( NULL ),
    _memorySizeNeeded ( 0 )
{
    _symbols = new SymbolTable;
}

CallingContext::~CallingContext ()
{
}

CallingInstance*
CallingContext::getInstance ( CallingInstance* caller )
{
    CallingInstance* instance = new CallingInstance ( this );
    instance->_callerContext = caller;
    return instance;
}

void
CallingContext::setCode ( Instruction* code )
{
    _code = code;
}

void
CallingContext::addParameter ( unsigned int index, Type type )
{
    _symbols->registerSymbol ( index );
    _declarationOrder.push_back ( index );
    _symbols->setCategoryOf ( index, PARAMETER );
    _symbols->setTypeOf ( index, type );
    _memorySizeNeeded += getTypeSize ( type );
}

void
CallingContext::addVariable ( unsigned int index, Type type )
{
    _symbols->registerSymbol ( index );
    _declarationOrder.push_back ( index );
    _symbols->setCategoryOf ( index, VARIABLE );
    _symbols->setTypeOf ( index, type );
    _memorySizeNeeded += getTypeSize ( type );
}

unsigned int
CallingContext::getArity () const
{
    return _declarationOrder.size ();
}

unsigned int
CallingContext::getParameterIndex ( const unsigned int idArg ) const
{
    return _declarationOrder [ idArg ];
}

Type
CallingContext::getTypeOf ( unsigned int index ) const
{
    return _symbols->getTypeOf ( index );
}

SymbolClass
CallingContext::getCategoryOf ( const unsigned int index ) const
{
    return _symbols->getCategoryOf ( index );
}

void
CallingContext::setName ( unsigned int index )
{
    _name = index;
}

void
CallingContext::setReturnType ( BaseType type )
{
    _returnType = type;
}

BaseType
CallingContext::getReturnType () const
{
    return _returnType;
}

void
displayTypedIdentificator ( unsigned int index, Type type )
{
    std::cout << type._base;
    if ( type._modifier == POINTER )
        std::cout << "*";
    std::cout << " " << ProgramManager::getNameOf ( index );
    if ( type._modifier == ARRAY )
        std::cout << " [ " << type._size << " ]";
}

void
CallingContext::display () const
{
    bool first = true;
    std::cout << _returnType << std::endl;
    std::cout << ProgramManager::getNameOf ( _name ) << " ( ";
    for ( unsigned int i = 0 ; i < _declarationOrder.size () ; i ++ )
    {
        if ( _symbols->getCategoryOf ( _declarationOrder [ i ] ) == PARAMETER )
        {
            if ( ! first )
                std::cout << ", ";
            displayTypedIdentificator ( _declarationOrder [ i ], _symbols->getTypeOf ( _declarationOrder [ i ] ) );
            first = false;
        }
    }
    std::cout << " )" << std::endl;
    for ( unsigned int i = 0 ; i < _declarationOrder.size () ; i ++ )
    {
        if ( _symbols->getCategoryOf ( _declarationOrder [ i ] ) == VARIABLE )
        {
            displayTypedIdentificator ( _declarationOrder [ i ], _symbols->getTypeOf ( _declarationOrder [ i ] ) );
            std::cout << ";" << std::endl;
        }
    }
    _code->display ();
}
